home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
GL
/
libdemo
/
spaced.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
25KB
|
1,082 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* Spaced: The Three-D Space Editor
*
* spaced.c
*
* This file, along with it's include file, spaced.h, contains
* all necessary routines for Spaced. See the comments in the include
* file for instructions on hooking it up to your code.
*
* Howard Look
* July, 1989
*
*/
#include <gl.h>
#include <device.h>
#include <math.h>
#include "spaced.h"
#define X 0
#define Y 1
#define Z 2
#define XY 2
#define XZ 1
#define YZ 0
#define NONE -1
#define EDGE_PICKED 99
/* Prototypes for internal functions */
static void transform_point(
Coord *,
Matrix,
Scoord *);
static float find_distance(
Scoord p[2],
Scoord q[2],
Scoord r[2]);
static float cos_angle_between(
Scoord center[2],
Scoord p1[2],
Scoord p2[2]);
static float dist(
Scoord p1[2],
Scoord p2[2]);
static void find_close(
Scoord m[2],
Scoord p[2],
Scoord q[3][2][2],
short a[2][2],
int i[3][2],
int);
static int length(Scoord axis[2][2]);
static Boolean colinear(Scoord axis1[2][2], Scoord axis2[2][2]);
/* window information */
static long origin_x, origin_y, size_x, size_y;
/* Which plane is motion constrained to */
static int plane;
static int edge;
static Coord initial_origin[3];
static Scoord initial_screen_origin[2];
static Boolean line_constrain, plane_constrain, first_time, constraint_ok;
static int colinear_threshold = SP_COLINEAR_THRESHOLD;
static int constraint_threshold = SP_CONSTRAINT_THRESHOLD;
static Device line_but1 = SP_LINE_BUTTON1;
static Device line_but2 = SP_LINE_BUTTON2;
static Device plane_but1 = SP_PLANE_BUTTON1;
static Device plane_but2 = SP_PLANE_BUTTON2;
/*
* Call this routine when you have completed all desired motion on a
* given point.
*/
void end_spaced(void)
{
/* A gratuitous function for future expansion */
}
/*
* Call this routine to change any of spaced's parameters from or to
* their default values. Calling with any parameter == -1 will reset
* that parameter to its default value.
*
* See the file spaced.h for a description of parameters and their
* default values.
*/
void set_spaced(
int col_thresh,
int const_thresh,
Device line1,
Device line2,
Device plane1,
Device plane2)
{
if (col_thresh == SP_DEFAULT)
colinear_threshold = SP_COLINEAR_THRESHOLD;
else
colinear_threshold = col_thresh;
if (const_thresh == SP_DEFAULT)
constraint_threshold = SP_CONSTRAINT_THRESHOLD;
else
constraint_threshold = const_thresh;
if (line1 == SP_DEFAULT)
line_but1 = SP_LINE_BUTTON1;
else
line_but1 = line1;
if (line2 == SP_DEFAULT)
line_but1 = SP_LINE_BUTTON1;
else
line_but1 = line2;
if (plane1 == SP_DEFAULT)
plane_but1 = SP_PLANE_BUTTON1;
else
plane_but1 = plane1;
if (plane2 == SP_DEFAULT)
plane_but1 = SP_PLANE_BUTTON2;
else
plane_but1 = plane2;
}
void start_spaced()
{
plane = NONE;
edge = NONE;
first_time = TRUE;
constraint_ok = FALSE;
}
static Matrix idmat=
{
1., 0., 0., 0.,
0., 1., 0., 0.,
0., 0., 1., 0.,
0., 0., 0., 1.,
};
/*
* The main routine. This is what you call to do update the position
* of a three-d point in world space.
*
* M is the matrix that gets your point from its world space into screen
* space. If you are in single matrix mode, just do a getmatrix and pass
* it here. If you are in double matrix mode, you will need to multiply
* the viewing matrix by the projection matrix to get the matrix needed here.
*
* origin is the coordinates of the point you wish to move. This routine
* will modify origin.
*
* limits specifies the bounding box that you wish origin to be contained
* within. It's format is limit[x=0, y=1, z=2][lo=0, hi=1]
*
* See the comments in spaced.h for more implementation information.
*/
int spaced(Matrix M, Coord origin[3], Coord limit[3][2])
{
/**************
* Declarations
**************/
/*
* Remember what mmode() the program is in; must save projection
* matrix if not MSINGLE
*/
int old_mmode;
/* Temporary matrix to squirrel away the projection matrix */
Matrix old_projection;
/* endpoint of line in world space projected from mouse pos'n */
Coord p1[3],p2[3];
/* dummy view object used to find that line using mapw */
static Object vobj;
/* Dont want to waste time and memory recreating that object */
static Boolean object_created = FALSE;
/* Mouse pos'n */
Scoord mouse[2];
/* Screen coords of the point being moved */
Scoord screen_motion_point[2];
/* Which axes mouse is between[axis 0,1][endpoint 0,1] */
static short between[2][2];
/* Your basic first-year geometry stuff */
Coord dx,dy,dz,x_slope,y_slope,z_slope,
x_int,y_int,z_int,x_proj,x_proj2,y_proj,y_proj2,z_proj,z_proj2;
/* Screen coords of the six axes endpoints
screen_axis[x,y,z][end 0,1][x,y] */
Scoord screen_axis[3][2][2];
/* used in finding screen axes */
Coord temp[3];
/* Is the point inside of the bounding volume ? */
Boolean within_bounds;
/*
* which axes to ignore when moving:
* at corners, ignore 3 of them
* at edges, ignore 2 of them
* at wall, ignore 1 of them
* inside, ignore none
*
* ignore[][0] = axis, ignore[1] = endpt */
int ignore[3][2];
int ignore_counter = 0;
/* loop variables */
int i,j;
Scoord temp_axis[2][2];
Boolean at_edge;
/* constraint value to return */
int constraint_return = SP_NONE;
/***********************
* Let the code begin...
***********************/
/* The mouse be here */
mouse[0] = getvaluator(MOUSEX);
mouse[1] = getvaluator(MOUSEY);
/* what the window is like */
getorigin(&origin_x, &origin_y);
getsize(&size_x, &size_y);
old_mmode = getmmode();
if (old_mmode != MSINGLE)
{
mmode(MPROJECTION);
getmatrix(old_projection);
loadmatrix(idmat);
mmode(MSINGLE);
}
/* create the dummy view object, if necessary */
if (! object_created)
{
vobj = genobj();
makeobj(vobj); closeobj();
object_created = TRUE;
}
/* use the current world->screen transformation */
pushmatrix();
delobj(vobj);
makeobj(vobj);
loadmatrix(M);
closeobj();
popmatrix();
/* find the line that the mouse position maps to in world space */
mapw(vobj, mouse[0]-origin_x, mouse[1]-origin_y,
&p1[0], &p1[1], &p1[2], &p2[0], &p2[1], &p2[2]);
/* find screen coords of the axes */
for (i=0; i<3; i++)
for (j=0; j<2; j++)
{
temp[0] = origin[0];
temp[1] = origin[1];
temp[2] = origin[2];
temp[i] = limit[i][j];
transform_point(temp, M, screen_axis[i][j]);
}
/* and of the point in motion */
temp[0] = origin[0];
temp[1] = origin[1];
temp[2] = origin[2];
transform_point(temp, M, screen_motion_point);
/* Check if constraining starts/stops */
plane_constrain = getbutton(plane_but1) || getbutton(plane_but2);
line_constrain = getbutton(line_but1) || getbutton(line_but2);
/* Line constraining is more constraining then plane constraining (!) */
if (line_constrain)
plane_constrain = FALSE;
/* Only pick a plane once if constraining, every time if not */
if ((! line_constrain) && (! plane_constrain))
{
plane = NONE;
constraint_ok = FALSE;
first_time = TRUE;
}
/* Setup initial constraint conditions */
if ((line_constrain || plane_constrain) && first_time)
{
first_time = FALSE;
plane = NONE;
initial_screen_origin[0] = screen_motion_point[0];
initial_screen_origin[1] = screen_motion_point[1];
initial_origin[0] = origin[0];
initial_origin[1] = origin[1];
initial_origin[2] = origin[2];
}
/* Check boundary conditions
* Only do this once if constraining
*/
if (plane == NONE)
{
within_bounds = TRUE;
ignore_counter = 0;
for(i=0; i<3; i++)
for(j=0; j<2; j++)
if (origin[i] == limit[i][j])
{
within_bounds = FALSE;
ignore[ignore_counter][0] = i;
ignore[ignore_counter][1] = j;
ignore_counter++;
}
}
at_edge = (ignore_counter >= 2);
/* Check if mouse has moved far enough to do constrained motion */
if ((line_constrain || plane_constrain) &&
(plane == NONE) &&
(!constraint_ok))
{
temp_axis[0][0] = (Scoord)(mouse[0]);
temp_axis[0][1] = (Scoord)(mouse[1]);
temp_axis[1][0] = initial_screen_origin[0];
temp_axis[1][1] = initial_screen_origin[1];
constraint_ok = (length(temp_axis) > SP_CONSTRAINT_THRESHOLD);
}
/* Check for axis colinearity. Ignore shorter of two colinear axes */
if ((within_bounds) && (plane == NONE))
{
if (colinear(screen_axis[0],screen_axis[1]))
if (length(screen_axis[0]) < length(screen_axis[1]))
{
ignore[ignore_counter][0] = 0;
ignore[ignore_counter][1] = 0;
ignore_counter++;
ignore[ignore_counter][0] = 0;
ignore[ignore_counter][1] = 1;
ignore_counter++;
}
else
{
ignore[ignore_counter][0] = 1;
ignore[ignore_counter][1] = 0;
ignore_counter++;
ignore[ignore_counter][0] = 1;
ignore[ignore_counter][1] = 1;
ignore_counter++;
}
else if (colinear(screen_axis[0],screen_axis[2]))
if (length(screen_axis[0]) < length(screen_axis[2]))
{
ignore[ignore_counter][0] = 0;
ignore[ignore_counter][1] = 0;
ignore_counter++;
ignore[ignore_counter][0] = 0;
ignore[ignore_counter][1] = 1;
ignore_counter++;
}
else
{
ignore[ignore_counter][0] = 2;
ignore[ignore_counter][1] = 0;
ignore_counter++;
ignore[ignore_counter][0] = 2;
ignore[ignore_counter][1] = 1;
ignore_counter++;
}
else if (colinear(screen_axis[1],screen_axis[2]))
if (length(screen_axis[1]) < length(screen_axis[2]))
{
ignore[ignore_counter][0] = 1;
ignore[ignore_counter][1] = 0;
ignore_counter++;
ignore[ignore_counter][0] = 1;
ignore[ignore_counter][1] = 1;
ignore_counter++;
}
else
{
ignore[ignore_counter][0] = 2;
ignore[ignore_counter][1] = 0;
ignore_counter++;
ignore[ignore_counter][0] = 2;
ignore[ignore_counter][1] = 1;
ignore_counter++;
}
}
if ((plane == NONE) &&
(((! line_constrain) && (! plane_constrain)) ||
((line_constrain || plane_constrain) && (constraint_ok))))
{
find_close(
mouse,screen_motion_point,screen_axis,between,ignore,ignore_counter);
if (! at_edge)
{
if ((between[0][0] != 0) && (between[1][0] != 0))
plane = YZ;
else if ((between[0][0] != 1) && (between[1][0] != 1))
plane = XZ;
else if ((between[0][0] != 2) && (between[1][0] != 2))
plane = XY;
}
else
{
edge = between[0][0];
plane = EDGE_PICKED;
}
}
/* Compute where the projected mouse position is */
if ((! at_edge)&&(plane == YZ))
{
/* Motion in Y-Z plane, X constant
Find where line hits the x=0 plane
As always, y = mx + b */
dx = p2[0] - p1[0];
if (dx != 0.0)
{
dy = p2[1] - p1[1];
dz = p2[2] - p1[2];
y_slope = dy/dx;
y_int = p2[1] - y_slope*p2[0]; /* at x = 0 */
y_proj = y_slope*origin[0] + y_int;
z_slope = dz/dx;
z_int = p2[2] - z_slope*p2[0];
z_proj = z_slope*origin[0] + z_int;
}
else
{
y_proj = p2[1];
z_proj = p2[2];
}
if ((! line_constrain) || (line_constrain && between[0][0] == 1) ||
plane_constrain)
if (y_proj <= limit[1][0])
origin[1] = limit[1][0];
else if (y_proj >= limit[1][1])
origin[1] = limit[1][1];
else
origin[1] = y_proj;
if ((! line_constrain) || (line_constrain && between[0][0] == 2) ||
plane_constrain)
if (z_proj <= limit[2][0])
origin[2] = limit[2][0];
else if (z_proj >= limit[2][1])
origin[2] = limit[2][1];
else
origin[2] = z_proj;
}
else if ((! at_edge)&&(plane == XZ))
{
/* Motion in X-Z plane, Y constant */
dy = p2[1] - p1[1];
if (dy != 0.0)
{
dx = p2[0] - p1[0];
dz = p2[2] - p1[2];
x_slope = dx/dy;
x_int = p2[0] - x_slope*p2[1]; /* at y = 0 */
x_proj = x_slope*origin[1] + x_int;
z_slope = dz/dy;
z_int = p2[2] - z_slope*p2[1];
z_proj = z_slope*origin[1] + z_int;
}
else
{
x_proj = p2[0];
z_proj = p2[2];
}
if ((! line_constrain) || (line_constrain && between[0][0] == 0) ||
plane_constrain)
if (x_proj <= limit[0][0])
origin[0] = limit[0][0];
else if (x_proj >= limit[0][1])
origin[0] = limit[0][1];
else
origin[0] = x_proj;
if ((! line_constrain) || (line_constrain && between[0][0] == 2) ||
plane_constrain)
if (z_proj <= limit[2][0])
origin[2] = limit[2][0];
else if (z_proj >= limit[2][1])
origin[2] = limit[2][1];
else
origin[2] = z_proj;
}
else if ((! at_edge)&&(plane == XY))
{
/* Motion in X-Y plane, Z constant */
dz = p2[2] - p1[2];
if (dz != 0.0)
{
dx = p2[0] - p1[0];
dy = p2[1] - p1[1];
x_slope = dx/dz;
x_int = p2[0] - x_slope*p2[2]; /* at z = 0 */
x_proj = x_slope*origin[2] + x_int;
y_slope = dy/dz;
y_int = p2[1] - y_slope*p2[2];
y_proj = y_slope*origin[2] + y_int;
}
else
{
x_proj = p2[0];
y_proj = p2[1];
}
if ((! line_constrain) || (line_constrain && between[0][0] == 0) ||
plane_constrain)
if (x_proj <= limit[0][0])
origin[0] = limit[0][0];
else if (x_proj >= limit[0][1])
origin[0] = limit[0][1];
else
origin[0] = x_proj;
if ((! line_constrain) || (line_constrain && between[0][0] == 1) ||
plane_constrain)
if (y_proj <= limit[1][0])
origin[1] = limit[1][0];
else if (y_proj >= limit[1][1])
origin[1] = limit[1][1];
else
origin[1] = y_proj;
}
else if (edge == X)
{
float cos_angle,base,hyp,slength,q1[3],q2[3];
Scoord sdx,sdy,newx,newy;
cos_angle=cos_angle_between(screen_axis[0][0],screen_axis[0][1],mouse);
hyp = dist(screen_axis[0][0],mouse);
base = hyp * cos_angle;
sdx = screen_axis[0][1][0] - screen_axis[0][0][0];
sdy = screen_axis[0][1][1] - screen_axis[0][0][1];
slength = fsqrt((float)(sdx*sdx + sdy*sdy));
newx = (Scoord) ( (float)screen_axis[0][0][0] +
((float)(screen_axis[0][1][0] - screen_axis[0][0][0]))*(base/slength));
newy = (Scoord) ( (float)screen_axis[0][0][1] +
((float)(screen_axis[0][1][1] - screen_axis[0][0][1]))*(base/slength));
mapw(vobj, newx-origin_x, newy-origin_y,
&q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
/* in XY plane... */
dz = q2[2] - q1[2];
if (dz != 0.0)
{
dx = q2[0] - q1[0];
dy = q2[1] - q1[1];
x_slope = dx/dz;
x_int = q2[0] - x_slope*q2[2]; /* at z = 0 */
x_proj = x_slope*origin[2] + x_int;
y_slope = dy/dz;
y_int = q2[1] - y_slope*q2[2];
y_proj = y_slope*origin[2] + y_int;
}
else
{
x_proj = q2[0];
y_proj = q2[1];
}
/* in XZ plane... */
dy = q2[1] - q1[1];
if (dy != 0.0)
{
dx = q2[0] - q1[0];
dz = q2[2] - q1[2];
x_slope = dx/dy;
x_int = q2[0] - x_slope*q2[1]; /* at y = 0 */
x_proj2 = x_slope*origin[1] + x_int;
z_slope = dz/dy;
z_int = q2[2] - z_slope*q2[1];
z_proj = z_slope*origin[1] + z_int;
}
else
{
x_proj2 = q2[0];
z_proj = q2[2];
}
origin[0] = x_proj - ((y_proj - origin[1])*(x_proj -
x_proj2)/(y_proj-z_proj));
if (origin[0] < limit[0][0])
origin[0] = limit[0][0];
else if (origin[0] > limit[0][1])
origin[0] = limit[0][1];
}
else if (edge == Y)
{
float cos_angle,base,hyp,slength,q1[3],q2[3];
Scoord sdx,sdy,newx,newy;
cos_angle=cos_angle_between(screen_axis[1][0],screen_axis[1][1],mouse);
hyp = dist(screen_axis[1][0],mouse);
base = hyp * cos_angle;
sdx = screen_axis[1][1][0] - screen_axis[1][0][0];
sdy = screen_axis[1][1][1] - screen_axis[1][0][1];
slength = fsqrt((float)(sdx*sdx + sdy*sdy));
newx = (Scoord) ( (float)screen_axis[1][0][0] +
((float)(screen_axis[1][1][0] - screen_axis[1][0][0]))*(base/slength));
newy = (Scoord) ( (float)screen_axis[1][0][1] +
((float)(screen_axis[1][1][1] - screen_axis[1][0][1]))*(base/slength));
mapw(vobj, newx-origin_x, newy-origin_y,
&q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
/* in XY plane... */
dz = q2[2] - q1[2];
if (dz != 0.0)
{
dx = q2[0] - q1[0];
dy = q2[1] - q1[1];
x_slope = dx/dz;
x_int = q2[0] - x_slope*q2[2]; /* at z = 0 */
x_proj = x_slope*origin[2] + x_int;
y_slope = dy/dz;
y_int = q2[1] - y_slope*q2[2];
y_proj = y_slope*origin[2] + y_int;
}
else
{
x_proj = q2[0];
y_proj = q2[1];
}
/* in YZ plane... */
dx = q2[0] - q1[0];
if (dx != 0.0)
{
dy = q2[1] - q1[1];
dz = q2[2] - q1[2];
y_slope = dy/dx;
y_int = q2[1] - y_slope*q2[0]; /* at x = 0 */
y_proj2 = y_slope*origin[0] + y_int;
z_slope = dz/dx;
z_int = q2[2] - z_slope*q2[0];
z_proj = z_slope*origin[0] + z_int;
}
else
{
y_proj2 = q2[1];
z_proj = q2[2];
}
origin[1] = y_proj2 - ((z_proj - origin[0])*(y_proj2 -
y_proj)/(z_proj-x_proj));
if (origin[1] < limit[1][0])
origin[1] = limit[1][0];
else if (origin[1] > limit[1][1])
origin[1] = limit[1][1];
}
else if (edge == Z)
{
float cos_angle,base,hyp,slength,q1[3],q2[3];
Scoord sdx,sdy,newx,newy;
cos_angle=cos_angle_between(screen_axis[2][0],screen_axis[2][1],mouse);
hyp = dist(screen_axis[2][0],mouse);
base = hyp * cos_angle;
sdx = screen_axis[2][1][0] - screen_axis[2][0][0];
sdy = screen_axis[2][1][1] - screen_axis[2][0][1];
slength = fsqrt((float)(sdx*sdx + sdy*sdy));
newx = (Scoord) ( (float)screen_axis[2][0][0] +
((float)(screen_axis[2][1][0] - screen_axis[2][0][0]))*(base/slength));
newy = (Scoord) ( (float)screen_axis[2][0][1] +
((float)(screen_axis[2][1][1] - screen_axis[2][0][1]))*(base/slength));
mapw(vobj, newx-origin_x, newy-origin_y,
&q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
/* in XZ plane... */
dy = q2[1] - q1[1];
if (dy != 0.0)
{
dx = q2[0] - q1[0];
dz = q2[2] - q1[2];
x_slope = dx/dy;
x_int = q2[0] - x_slope*q2[1]; /* at y = 0 */
x_proj = x_slope*origin[1] + x_int;
z_slope = dz/dy;
z_int = q2[2] - z_slope*q2[1];
z_proj = z_slope*origin[1] + z_int;
}
else
{
x_proj = q2[0];
z_proj = q2[2];
}
/* in YZ plane... */
dx = q2[0] - q1[0];
if (dx != 0.0)
{
dy = q2[1] - q1[1];
dz = q2[2] - q1[2];
y_slope = dy/dx;
y_int = q2[1] - y_slope*q2[0]; /* at x = 0 */
y_proj = y_slope*origin[0] + y_int;
z_slope = dz/dx;
z_int = q2[2] - z_slope*q2[0];
z_proj2 = z_slope*origin[0] + z_int;
}
else
{
y_proj = q2[1];
z_proj2 = q2[2];
}
origin[2] = z_proj2 - ((x_proj - origin[1])*(z_proj2 -
z_proj)/(x_proj-y_proj));
if (origin[2] < limit[2][0])
origin[2] = limit[2][0];
else if (origin[2] > limit[2][1])
origin[2] = limit[2][1];
}
if (old_mmode != MSINGLE);
{
mmode(MPROJECTION);
loadmatrix(old_projection);
mmode(old_mmode);
}
if (plane_constrain)
switch (plane)
{
case YZ: constraint_return = SP_YZ_PLANE; break;
case XZ: constraint_return = SP_XZ_PLANE; break;
case XY: constraint_return = SP_XY_PLANE; break;
}
else if (line_constrain)
switch (plane)
{
case YZ:
if (between[0][0] == 2)
constraint_return = SP_Z_AXIS;
else
constraint_return = SP_Y_AXIS;
break;
case XZ:
if (between[0][0] == 2)
constraint_return = SP_Z_AXIS;
else
constraint_return = SP_X_AXIS;
break;
case XY:
if (between[0][0] == 1)
constraint_return = SP_Y_AXIS;
else
constraint_return = SP_X_AXIS;
break;
}
return constraint_return;
}
/* In variable between, returns which two axis the mouse position is
* between. There are six possible axes, pos and neg for each of x,y,z.
* The closest axis to the mouse position will be in between[0], and
* the next closest will be in between[1].
*
* if ignore is set to 0,1 or 2, that axis will be ignore.
*
* Example: if
* between[0][0] = 1, between[0][1] = 0
* between[1][0] = 2, between[1][1] = 1
*
* means that the mouse is between axis 1, endpoint 0 and axis 2, endpoint 1.
* Translated, the mouse is between the negative Y and positive Z axes,
* closer to Y.
*/
static void find_close(
Scoord mouse[2],
Scoord center[2],
Scoord screen_axis[3][2][2],
short between[2][2],
int ignore[3][2],
int ignore_counter)
{
short i, j, k;
float distance,max1,max2;
max1 = max2 = -2.0; /* nothing will ever be less than -1.0 */
/* find distance from mouse vector to the six axes */
for(i=0;i<3;i++)
for(j=0;j<2;j++)
{
distance = 0.0;
for (k=0; k<ignore_counter; k++)
if ((i == ignore[k][0]) && (j == ignore[k][1]))
distance = -2.0;
if (distance == 0.0)
distance = find_distance(center, mouse, screen_axis[i][j] );
if (distance > max1)
{
between[1][0] = between[0][0];
between[1][1] = between[0][1];
between[0][0] = i;
between[0][1] = j;
max2 = max1;
max1 = distance;
}
else if (distance > max2)
{
between[1][0] = i;
between[1][1] = j;
max2 = distance;
}
}
}
/* Returns the length of the axis. */
static int length(Scoord axis[2][2])
{
int dx,dy;
dx = axis[1][0] - axis[0][0];
dy = axis[1][1] - axis[0][1];
return ((int)fsqrt((float)(dx*dx + dy*dy)));
}
/* Finds the "distance" between the two vectors from center to p1, and
* center to p2. Actually returns the dot product, normalized 0.0 to 1.0.
*/
static float find_distance(Scoord center[2], Scoord p1[2], Scoord p2[2])
{
float result,v1[2],v2[2],n1,n2;
v1[0] = (float)p1[0] - (float)center[0];
v1[1] = (float)p1[1] - (float)center[1];
v2[0] = (float)p2[0] - (float)center[0];
v2[1] = (float)p2[1] - (float)center[1];
n1 = fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
n2 = fsqrt(v2[0]*v2[0] + v2[1]*v2[1]);
result = (v1[0]/n1)*(v2[0]/n2) + (v1[1]/n1)*(v2[1]/n2);
return(result);
}
/*
Returns the cosine of angle between the vectors P1 and P2 with common start
point center
*/
static float cos_angle_between(Scoord center[2], Scoord p1[2], Scoord p2[2])
{
float v1[2],v2[2],n1,n2;
v1[0] = (float)p1[0] - (float)center[0];
v1[1] = (float)p1[1] - (float)center[1];
v2[0] = (float)p2[0] - (float)center[0];
v2[1] = (float)p2[1] - (float)center[1];
n1 = fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
n2 = fsqrt(v2[0]*v2[0] + v2[1]*v2[1]);
return (v1[0]*v2[0] + v1[1]*v2[1])/(n1*n2);
}
static float dist(Scoord p1[2], Scoord p2[2])
{
float result,v1[2];
v1[0] = (float)p2[0] - (float)p1[0];
v1[1] = (float)p2[1] - (float)p1[1];
return fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
}
/*
* Takes a world coordinate (x,y,z) and pumps it through tranformation
* matrix M, returning the screen coordinate in result.
*
* Note: One could use feedback to do this, but it turns out to be
* faster to do it manually.
*/
static void transform_point(Coord *p, Matrix M, Scoord *result)
{
Coord x,y,z,w,hx,hy;
x = p[0]*M[0][0] + p[1]*M[1][0] + p[2]*M[2][0] + M[3][0];
y = p[0]*M[0][1] + p[1]*M[1][1] + p[2]*M[2][1] + M[3][1];
z = p[0]*M[0][2] + p[1]*M[1][2] + p[2]*M[2][2] + M[3][2];
w = p[0]*M[0][3] + p[1]*M[1][3] + p[2]*M[2][3] + M[3][3];
/* Homogeneous coords b/w -1 and 1 */
hx = x/w;
hy = y/w;
result[0] = (Scoord)((1.0 + hx)*(Coord)size_x/2.0) + origin_x;
result[1] = (Scoord)((1.0 + hy)*(Coord)size_y/2.0) + origin_y;
}
/*
* Returns TRUE if the two axes are colinear within COLINEAR_THRESHOLD
* pixels.
*
* Finds the distance from endpoint of one two line of other.
* Taken from handbook of mathematical tables... p. 159
*/
static Boolean colinear(Scoord a1[2][2], Scoord a2[2][2])
{
float dx,dy,m,b,A,B,C,dist1,dist2;
dx = (float)(a1[0][0] - a1[1][0]);
if (dx == 0.0)
dx = 0.0001;
dy = (float)(a1[0][1] - a1[1][1]);
m = dy/dx; /* slope */
b = (float)a1[0][1] - m*(float)a1[0][0]; /* y intercept */
A = -m;
B = 1.0;
C = -b;
dist1 = (A*(float)a2[0][0] + B*(float)a2[0][1] + C)/
fsqrt(A*A + B*B);
dist2 = (A*(float)a2[1][0] + B*(float)a2[1][1] + C)/
fsqrt(A*A + B*B);
if ((fabs(dist1) < (float)SP_COLINEAR_THRESHOLD) && (fabs(dist2) < (float)SP_COLINEAR_THRESHOLD))
return TRUE;
else
return FALSE;
}